package c10异常;

/**
 * 测试return、throw、System.exit(int)与finally代码块的执行顺序。我的总结：
 * <p>
 * 通常情况下，return、throw语句都可以立即终止当前的方法，后面的代码都不会被执行。
 * 但是，放在try、catch语句块内时，并不会立即执行，而是先查看有没有finally语句块：若无，照常；
 * 否则，先把return值（若有的话）、throw的异常对象压栈，再去执行finally的语句；若finally内没有return、throw语句，
 * 执行完后马上return或throw出保存在栈中的值；否则，在finally中return、throw而结束方法，栈中保存返回值和异常对象
 * 和其他局部变量一样随着方法的生命周期结束一同被销毁了！所以我们才看到了下面这些测试结果！
 * 单是returnAndFinally2这个例子就证明了李刚老师的说法是错误的！
 * 特例：throwAndFinally中，如果try内的throw能被catch捕获，则不会受finally的throw影响，否则如上。
 * <p>
 * 如果在try或catch中调用System.exit(int)，将会退出虚拟机，finally块直接被无视！
 *
 * @author 炜sama
 */
public class 探究finally块的代码执行顺序 {

    public static void main(String[] args) {
//		System.err.println("main" + returnAndFinally());//不是1是0！
//        System.err.println("main" + returnAndFinally2());//不是1是3！

//		try {
//			throwAndFinally();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}

//		throwAndReturn();
		exitAndFinally();
    }

    static int returnAndFinally() {
        int i = 0;
        try {
            System.err.println("try" + i);
            return i;//i被押栈，然后才去执行finally
        } finally {
            ++i;//这里的i是局部变量i，修改它不会影响到保存在栈中的函数返回值！
            System.err.println("finally" + i);
        }
    }

    static int returnAndFinally2() {
        try {
            System.err.println("try");
            return 1;//1被押栈，然后才去执行finally
        } finally {
            System.err.println("finally");
            return 3;//直接返回3，方法结束！上面保存的1随着方法结束而被销毁了！
        }
    }

    static void throwAndFinally() {
        try {
            System.err.println("try");
            //try中的异常如果能被catch捕获，则进入catch块，不受finally抛出的异常影响；
            //否则，待遇与catch中的throw一样！
//            throw new NullPointerException("Exception in try");//能被catch捕获
			int i = 1 / 0;//不能被catch捕获
//			return;
        } catch (NullPointerException e) {
            System.err.println(e.getMessage());
            throw new RuntimeException("Exception in catch");//匿名异常对象被押栈！
        } finally {
            System.err.println("finally");
//            throw new NullPointerException("Exception in finally");//这个异常覆盖了上面所有的异常, 直接结束方法！
			return;//直接结束方法！
        }
    }

    static void throwAndReturn() {
        try {
            throw new Exception("xxx");
        } finally {
            return;
        }
    }

    static void exitAndFinally() {
        try {
            System.err.println("try");
            System.exit(0);//强制退出虚拟机！
        } finally {
            System.err.println("finally");//不会被执行！
        }
    }
}
